package com.nx.platform.es.common.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Thread local DateFormt util
 *
 * @author
 * @since Aug 1, 2015
 */
public final class DateFormatUtil {

    private static final ConcurrentMap<String, ThreadLocal<DateFormat>> HOLDER_MAP = new ConcurrentHashMap<>();

    /**
     * Formats a Date into a date/time string.
     *
     * @param pattern the pattern describing the date and time format.
     * @param date the time value to be formatted into a time string.
     * @return the formatted time string.
     * @see DateFormat#format(Date)
     */
    public static String format(String pattern, Date date) {
        return getDateFormat(pattern).format(date);
    }

    /**
     * Parses text from the beginning of the given string to produce a date. The
     * method may not use the entire text of the given string.
     *
     * @param pattern the pattern describing the date and time format.
     * @param source A String whose beginning should be parsed.
     * @return A Date parsed from the string.
     * @throws ParseException - if the beginning of the specified string cannot be parsed.
     * @see DateFormat#parse(String)
     */
    public static Date parse(String pattern, String source) throws ParseException {
        return getDateFormat(pattern).parse(source);
    }

    /**
     * Returns a SimpleDateFormat using the given pattern and the default date
     * format symbols for the default locale.
     *
     * @param pattern the pattern describing the date and time format
     * @return a SimpleDateFormat using the given pattern and the default date
     * format symbols for the default locale.
     * @throws NullPointerException - if the given pattern is null
     * @throws IllegalArgumentException - if the given pattern is invalid
     */
    private static DateFormat getDateFormat(String pattern) {
        if (pattern == null) {
            throw new NullPointerException("pattern");
        }
        ThreadLocal<DateFormat> threadLocal;
        if ((threadLocal = HOLDER_MAP.get(pattern)) == null) {
            synchronized (HOLDER_MAP) {
                if ((threadLocal = HOLDER_MAP.get(pattern)) == null) {
                    // If pattern invalid, there will be a
                    // IllegalArgumentException here.
                    DateFormat dateFormat = new SimpleDateFormat(pattern);
                    dateFormat.setCalendar(Calendar.getInstance(Locale.ENGLISH));
                    threadLocal = new ThreadLocal<>();
                    threadLocal.set(dateFormat);
                    HOLDER_MAP.put(pattern, threadLocal);
                    return dateFormat;
                }
            }
        }
        DateFormat dateFormat = threadLocal.get();
        if (dateFormat == null) {
            dateFormat = new SimpleDateFormat(pattern);
            threadLocal.set(dateFormat);
        }
        return dateFormat;
    }

}
